For this project you will be doing the Bike Sharing Demand Kaggle challenge!. The main point of this project is to get you feeling comfortabe with Exploratory Data Analysis and begin to get an understanding that sometimes certain models are not a good choice for a data set. In this case, we will discover that Linear Regression may not be the best choice given our data!
Instructions
Just complete the tasks outlined below.
Get the Data
You can download the data or just use the supplied csv in the repository. The data has the following features:
- datetime - hourly date + timestamp
- season - 1 = spring, 2 = summer, 3 = fall, 4 = winter
- holiday - whether the day is considered a holiday
- workingday - whether the day is neither a weekend nor holiday
- weather -
- 1: Clear, Few clouds, Partly cloudy, Partly cloudy
- 2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
- 3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
- 4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog
- temp - temperature in Celsius
- atemp - “feels like” temperature in Celsius
- humidity - relative humidity
- windspeed - wind speed
- casual - number of non-registered user rentals initiated
- registered - number of registered user rentals initiated
- count - number of total rentals
Read in bikeshare.csv file and set it to a dataframe called bike.
remove(list = ls())
bike <- read.csv('/Users/sobil/Documents/Certifications/DataScienceAndMachineLearningBootcampWithRUdemy/Notes/Training Exercises/Machine Learning Projects/CSV files for ML Projects/bikeshare.csv', stringsAsFactors = FALSE)
Check the head of df
head(bike)
Exploratory Data Analysis
Create a scatter plot of count vs temp. Set a good alpha value.
library(ggplot2)
ggplot(data = bike, aes(x = temp, y = count)) + geom_point(aes(color = temp, alpha = 0.5))

Plot count versus datetime as a scatterplot with a color gradient based on temperature. You’ll need to convert the datetime column into POSIXct before plotting.
ggplot(data = bike, aes(x = as.POSIXct(datetime), y = count)) + geom_point(aes(alpha = 0.5, color = temp)) + scale_color_gradient(low = "darkgreen", high = "orange")

Noticed two things: A seasonality to the data, for winter and summer. Also that bike rental counts are increasing in general. This may present a problem with using a linear regression model if the data is non-linear. Let’s have a quick overview of pros and cons right now of Linear Regression:
Pros:
- Simple to explain
- Highly interpretable
- Model training and prediction are fast
- No tuning is required (excluding regularization)
- Features don’t need scaling
- Can perform well with a small number of observations
- Well-understood
Cons:
- Assumes a linear relationship between the features and the response
- Performance is (generally) not competitive with the best supervised learning methods due to high bias
- Can’t automatically learn feature interactions
We’ll keep this in mind as we continue on. Maybe when we learn more algorithms we can come back to this with some new tools, for now we’ll stick to Linear Regression.
What is the correlation between temp and count?
cor(bike$temp, bike$count)
[1] 0.3944536
Let’s explore the season data. Create a boxplot, with the y axis indicating count and the x axis begin a box for each season.
ggplot(data = bike, aes(y = count, x = factor(season))) + geom_boxplot(aes(color = factor(season)))

Notice what this says:
A line can’t capture a non-linear relationship. There are more rentals in winter than in spring
We know of these issues because of the growth of rental count, this isn’t due to the actual season!
Feature Engineering
A lot of times you’ll need to use domain knowledge and experience to engineer and create new features. Let’s go ahead and engineer some new features from the datetime column.
Create an “hour” column that takes the hour from the datetime column. You’ll probably need to apply some function to the entire datetime column and reassign it. Hint:
time.stamp <- bike$datetime format(time.stamp, “%H”)
Now create a scatterplot of count versus hour, with color scale based on temp. Only use bike data where workingday==1.
Optional Additions:
Use the additional layer: scale_color_gradientn(colors=c(‘color1’,color2,etc..)) where the colors argument is a vector gradient of colors you choose, not just high and low. Use position=position_jitter(w=1, h=0) inside of geom_point() and check out what it does.

Now create the same plot for non working days:

You should have noticed that working days have peak activity during the morning (~8am) and right after work gets out (~5pm), with some lunchtime activity. While the non-work days have a steady rise and fall for the afternoon
Now let’s continue by trying to build a model, we’ll begin by just looking at a single feature.
Building the Model
Use lm() to build a model that predicts count based solely on the temp feature, name it temp.model
Get the summary of the temp.model
summary(temp.model)
Call:
lm(formula = count ~ temp, data = bike)
Residuals:
Min 1Q Median 3Q Max
-293.32 -112.36 -33.36 78.98 741.44
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 6.0462 4.4394 1.362 0.173
temp 9.1705 0.2048 44.783 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 166.5 on 10884 degrees of freedom
Multiple R-squared: 0.1556, Adjusted R-squared: 0.1555
F-statistic: 2006 on 1 and 10884 DF, p-value: < 2.2e-16
How many bike rentals would we predict if the temperature was 25 degrees Celsius? Calculate this two ways:
- Using the values we just got above
- Using the predict() function You should get around 235.3 bikes.
6.0462 + 9.1705*25
[1] 235.3087
predict(temp.model, data.frame(temp = c(25)))
1
235.3097
Use sapply() and as.numeric to change the hour column to a column of numeric values.
Get the summary of the model
summary(lm.model)
Call:
lm(formula = count ~ . - casual - registered - datetime - atemp,
data = bike)
Residuals:
Min 1Q Median 3Q Max
-324.61 -96.88 -31.01 55.27 688.83
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 46.91369 8.45147 5.551 2.91e-08 ***
season 21.70333 1.35409 16.028 < 2e-16 ***
holiday -10.29914 8.79069 -1.172 0.241
workingday -0.71781 3.14463 -0.228 0.819
weather -3.20909 2.49731 -1.285 0.199
temp 7.01953 0.19135 36.684 < 2e-16 ***
humidity -2.21174 0.09083 -24.349 < 2e-16 ***
windspeed 0.20271 0.18639 1.088 0.277
hour 7.61283 0.21688 35.102 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 147.8 on 10877 degrees of freedom
Multiple R-squared: 0.3344, Adjusted R-squared: 0.3339
F-statistic: 683 on 8 and 10877 DF, p-value: < 2.2e-16
Did the model perform well on the training data? What do you think about using a Linear Model on this data?
You should have noticed that this sort of model doesn’t work well given our seasonal and time series data. We need a model that can account for this type of trend, read about Regression Forests for more info if you’re interested! For now, let’s keep this in mind as a learning experience and move on towards classification with Logistic Regression!
ARIMA model can also is better option in predicting time series
Optional: See how well you can predict for future data points by creating a train/test split. But instead of a random split, your split should be “future” data for test, “previous” data for train.
Great Job!
LS0tCnRpdGxlOiAiTGluZWFyIFJlZ3Jlc3Npb24gUHJvamVjdCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKRm9yIHRoaXMgcHJvamVjdCB5b3Ugd2lsbCBiZSBkb2luZyB0aGUgQmlrZSBTaGFyaW5nIERlbWFuZCBLYWdnbGUgY2hhbGxlbmdlIS4gVGhlIG1haW4gcG9pbnQgb2YgdGhpcyBwcm9qZWN0IGlzIHRvIGdldCB5b3UgZmVlbGluZyBjb21mb3J0YWJlIHdpdGggRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBhbmQgYmVnaW4gdG8gZ2V0IGFuIHVuZGVyc3RhbmRpbmcgdGhhdCBzb21ldGltZXMgY2VydGFpbiBtb2RlbHMgYXJlIG5vdCBhIGdvb2QgY2hvaWNlIGZvciBhIGRhdGEgc2V0LiBJbiB0aGlzIGNhc2UsIHdlIHdpbGwgZGlzY292ZXIgdGhhdCBMaW5lYXIgUmVncmVzc2lvbiBtYXkgbm90IGJlIHRoZSBiZXN0IGNob2ljZSBnaXZlbiBvdXIgZGF0YSEKCiMjIEluc3RydWN0aW9ucwpKdXN0IGNvbXBsZXRlIHRoZSB0YXNrcyBvdXRsaW5lZCBiZWxvdy4KCiMjIEdldCB0aGUgRGF0YQpZb3UgY2FuIGRvd25sb2FkIHRoZSBkYXRhIG9yIGp1c3QgdXNlIHRoZSBzdXBwbGllZCBjc3YgaW4gdGhlIHJlcG9zaXRvcnkuIFRoZSBkYXRhIGhhcyB0aGUgZm9sbG93aW5nIGZlYXR1cmVzOgoKKiBkYXRldGltZSAtIGhvdXJseSBkYXRlICsgdGltZXN0YW1wCiogc2Vhc29uIC0gMSA9IHNwcmluZywgMiA9IHN1bW1lciwgMyA9IGZhbGwsIDQgPSB3aW50ZXIKKiBob2xpZGF5IC0gd2hldGhlciB0aGUgZGF5IGlzIGNvbnNpZGVyZWQgYSBob2xpZGF5Ciogd29ya2luZ2RheSAtIHdoZXRoZXIgdGhlIGRheSBpcyBuZWl0aGVyIGEgd2Vla2VuZCBub3IgaG9saWRheQoqIHdlYXRoZXIgLQogICsgMTogQ2xlYXIsIEZldyBjbG91ZHMsIFBhcnRseSBjbG91ZHksIFBhcnRseSBjbG91ZHkKICArIDI6IE1pc3QgKyBDbG91ZHksIE1pc3QgKyBCcm9rZW4gY2xvdWRzLCBNaXN0ICsgRmV3IGNsb3VkcywgTWlzdAogICsgMzogTGlnaHQgU25vdywgTGlnaHQgUmFpbiArIFRodW5kZXJzdG9ybSArIFNjYXR0ZXJlZCBjbG91ZHMsIExpZ2h0IFJhaW4gKyBTY2F0dGVyZWQgY2xvdWRzCiAgKyA0OiBIZWF2eSBSYWluICsgSWNlIFBhbGxldHMgKyBUaHVuZGVyc3Rvcm0gKyBNaXN0LCBTbm93ICsgRm9nCiogdGVtcCAtIHRlbXBlcmF0dXJlIGluIENlbHNpdXMKKiBhdGVtcCAtICJmZWVscyBsaWtlIiB0ZW1wZXJhdHVyZSBpbiBDZWxzaXVzCiogaHVtaWRpdHkgLSByZWxhdGl2ZSBodW1pZGl0eQoqIHdpbmRzcGVlZCAtIHdpbmQgc3BlZWQKKiBjYXN1YWwgLSBudW1iZXIgb2Ygbm9uLXJlZ2lzdGVyZWQgdXNlciByZW50YWxzIGluaXRpYXRlZAoqIHJlZ2lzdGVyZWQgLSBudW1iZXIgb2YgcmVnaXN0ZXJlZCB1c2VyIHJlbnRhbHMgaW5pdGlhdGVkCiogY291bnQgLSBudW1iZXIgb2YgdG90YWwgcmVudGFscwoKIyMjIyBSZWFkIGluIGJpa2VzaGFyZS5jc3YgZmlsZSBhbmQgc2V0IGl0IHRvIGEgZGF0YWZyYW1lIGNhbGxlZCBiaWtlLgpgYGB7cn0KcmVtb3ZlKGxpc3QgPSBscygpKQpiaWtlIDwtIHJlYWQuY3N2KCcvVXNlcnMvc29iaWwvRG9jdW1lbnRzL0NlcnRpZmljYXRpb25zL0RhdGFTY2llbmNlQW5kTWFjaGluZUxlYXJuaW5nQm9vdGNhbXBXaXRoUlVkZW15L05vdGVzL1RyYWluaW5nIEV4ZXJjaXNlcy9NYWNoaW5lIExlYXJuaW5nIFByb2plY3RzL0NTViBmaWxlcyBmb3IgTUwgUHJvamVjdHMvYmlrZXNoYXJlLmNzdicsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKYGBgCgojIyMjIENoZWNrIHRoZSBoZWFkIG9mIGRmCmBgYHtyfQpoZWFkKGJpa2UpCmBgYAoKIyMjIyBDYW4geW91IGZpZ3VyZSBvdXQgd2hhdCBpcyB0aGUgdGFyZ2V0IHdlIGFyZSB0cnlpbmcgdG8gcHJlZGljdD8gQ2hlY2sgdGhlIEthZ2dsZSBMaW5rIGFib3ZlIGlmIHlvdSBhcmUgY29uZnVzZWQgb24gdGhpcy4KYGBge3J9CnN0cihiaWtlJGNvdW50KQpgYGAKIyMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcwojIyMjIENyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBvZiBjb3VudCB2cyB0ZW1wLiBTZXQgYSBnb29kIGFscGhhIHZhbHVlLgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBiaWtlLCBhZXMoeCA9IHRlbXAsIHkgPSBjb3VudCkpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSB0ZW1wLCBhbHBoYSA9IDAuNSkpCmBgYAoKIyMjIyBQbG90IGNvdW50IHZlcnN1cyBkYXRldGltZSBhcyBhIHNjYXR0ZXJwbG90IHdpdGggYSBjb2xvciBncmFkaWVudCBiYXNlZCBvbiB0ZW1wZXJhdHVyZS4gWW91J2xsIG5lZWQgdG8gY29udmVydCB0aGUgZGF0ZXRpbWUgY29sdW1uIGludG8gUE9TSVhjdCBiZWZvcmUgcGxvdHRpbmcuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBiaWtlLCBhZXMoeCA9IGFzLlBPU0lYY3QoZGF0ZXRpbWUpLCB5ID0gY291bnQpKSArIGdlb21fcG9pbnQoYWVzKGFscGhhID0gMC41LCBjb2xvciA9IHRlbXApKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJkYXJrZ3JlZW4iLCBoaWdoID0gIm9yYW5nZSIpCmBgYAoKIyMjIyBOb3RpY2VkIHR3byB0aGluZ3M6IEEgc2Vhc29uYWxpdHkgdG8gdGhlIGRhdGEsIGZvciB3aW50ZXIgYW5kIHN1bW1lci4gQWxzbyB0aGF0IGJpa2UgcmVudGFsIGNvdW50cyBhcmUgaW5jcmVhc2luZyBpbiBnZW5lcmFsLiBUaGlzIG1heSBwcmVzZW50IGEgcHJvYmxlbSB3aXRoIHVzaW5nIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgaWYgdGhlIGRhdGEgaXMgbm9uLWxpbmVhci4gTGV0J3MgaGF2ZSBhIHF1aWNrIG92ZXJ2aWV3IG9mIHByb3MgYW5kIGNvbnMgcmlnaHQgbm93IG9mIExpbmVhciBSZWdyZXNzaW9uOgojIyMjIyBQcm9zOgoqIFNpbXBsZSB0byBleHBsYWluCiogSGlnaGx5IGludGVycHJldGFibGUKKiBNb2RlbCB0cmFpbmluZyBhbmQgcHJlZGljdGlvbiBhcmUgZmFzdAoqIE5vIHR1bmluZyBpcyByZXF1aXJlZCAoZXhjbHVkaW5nIHJlZ3VsYXJpemF0aW9uKQoqIEZlYXR1cmVzIGRvbid0IG5lZWQgc2NhbGluZwoqIENhbiBwZXJmb3JtIHdlbGwgd2l0aCBhIHNtYWxsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMKKiBXZWxsLXVuZGVyc3Rvb2QKCiMjIyMjIENvbnM6CiogQXNzdW1lcyBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZmVhdHVyZXMgYW5kIHRoZSByZXNwb25zZQoqIFBlcmZvcm1hbmNlIGlzIChnZW5lcmFsbHkpIG5vdCBjb21wZXRpdGl2ZSB3aXRoIHRoZSBiZXN0IHN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kcyBkdWUgdG8gaGlnaCBiaWFzCiogQ2FuJ3QgYXV0b21hdGljYWxseSBsZWFybiBmZWF0dXJlIGludGVyYWN0aW9ucwoKIyMjIyBXZSdsbCBrZWVwIHRoaXMgaW4gbWluZCBhcyB3ZSBjb250aW51ZSBvbi4gTWF5YmUgd2hlbiB3ZSBsZWFybiBtb3JlIGFsZ29yaXRobXMgd2UgY2FuIGNvbWUgYmFjayB0byB0aGlzIHdpdGggc29tZSBuZXcgdG9vbHMsIGZvciBub3cgd2UnbGwgc3RpY2sgdG8gTGluZWFyIFJlZ3Jlc3Npb24uCgojIyMjIFdoYXQgaXMgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGVtcCBhbmQgY291bnQ/CmBgYHtyfQpjb3IoYmlrZSR0ZW1wLCBiaWtlJGNvdW50KQpgYGAKIyMjIyBMZXQncyBleHBsb3JlIHRoZSBzZWFzb24gZGF0YS4gQ3JlYXRlIGEgYm94cGxvdCwgd2l0aCB0aGUgeSBheGlzIGluZGljYXRpbmcgY291bnQgYW5kIHRoZSB4IGF4aXMgYmVnaW4gYSBib3ggZm9yIGVhY2ggc2Vhc29uLgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBiaWtlLCBhZXMoeSA9IGNvdW50LCB4ID0gZmFjdG9yKHNlYXNvbikpKSArIGdlb21fYm94cGxvdChhZXMoY29sb3IgPSBmYWN0b3Ioc2Vhc29uKSkpCmBgYAoKIyMjIyBOb3RpY2Ugd2hhdCB0aGlzIHNheXM6CkEgbGluZSBjYW4ndCBjYXB0dXJlIGEgbm9uLWxpbmVhciByZWxhdGlvbnNoaXAuClRoZXJlIGFyZSBtb3JlIHJlbnRhbHMgaW4gd2ludGVyIHRoYW4gaW4gc3ByaW5nCgojIyMjIyBXZSBrbm93IG9mIHRoZXNlIGlzc3VlcyBiZWNhdXNlIG9mIHRoZSBncm93dGggb2YgcmVudGFsIGNvdW50LCB0aGlzIGlzbid0IGR1ZSB0byB0aGUgYWN0dWFsIHNlYXNvbiEKCiMjIEZlYXR1cmUgRW5naW5lZXJpbmcKQSBsb3Qgb2YgdGltZXMgeW91J2xsIG5lZWQgdG8gdXNlIGRvbWFpbiBrbm93bGVkZ2UgYW5kIGV4cGVyaWVuY2UgdG8gZW5naW5lZXIgYW5kIGNyZWF0ZSBuZXcgZmVhdHVyZXMuIExldCdzIGdvIGFoZWFkIGFuZCBlbmdpbmVlciBzb21lIG5ldyBmZWF0dXJlcyBmcm9tIHRoZSBkYXRldGltZSBjb2x1bW4uCgojIyMjIENyZWF0ZSBhbiAiaG91ciIgY29sdW1uIHRoYXQgdGFrZXMgdGhlIGhvdXIgZnJvbSB0aGUgZGF0ZXRpbWUgY29sdW1uLiBZb3UnbGwgcHJvYmFibHkgbmVlZCB0byBhcHBseSBzb21lIGZ1bmN0aW9uIHRvIHRoZSBlbnRpcmUgZGF0ZXRpbWUgY29sdW1uIGFuZCByZWFzc2lnbiBpdC4gSGludDoKdGltZS5zdGFtcCA8LSBiaWtlJGRhdGV0aW1lCmZvcm1hdCh0aW1lLnN0YW1wLCAiJUgiKQpgYGB7cn0KYmlrZSRob3VyIDwtIHN0cmZ0aW1lKGJpa2UkZGF0ZXRpbWUsIGZvcm1hdD0iJUgiKQpoZWFkKGJpa2UpCmBgYAojIyMjIE5vdyBjcmVhdGUgYSBzY2F0dGVycGxvdCBvZiBjb3VudCB2ZXJzdXMgaG91ciwgd2l0aCBjb2xvciBzY2FsZSBiYXNlZCBvbiB0ZW1wLiBPbmx5IHVzZSBiaWtlIGRhdGEgd2hlcmUgd29ya2luZ2RheT09MS4KIyMjIyBPcHRpb25hbCBBZGRpdGlvbnM6ClVzZSB0aGUgYWRkaXRpb25hbCBsYXllcjogc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycz1jKCdjb2xvcjEnLGNvbG9yMixldGMuLikpIHdoZXJlIHRoZSBjb2xvcnMgYXJndW1lbnQgaXMgYSB2ZWN0b3IgZ3JhZGllbnQgb2YgY29sb3JzIHlvdSBjaG9vc2UsIG5vdCBqdXN0IGhpZ2ggYW5kIGxvdy4KVXNlIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3PTEsIGg9MCkgaW5zaWRlIG9mIGdlb21fcG9pbnQoKSBhbmQgY2hlY2sgb3V0IHdoYXQgaXQgZG9lcy4KYGBge3J9CmdncGxvdChkYXRhID0gc3Vic2V0KHggPSBiaWtlLCBzdWJzZXQgPSB3b3JraW5nZGF5ID09IDEpLCBhZXMoeCA9IGhvdXIsIHkgPSBjb3VudCkpICsgZ2VvbV9wb2ludChwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIodz0xLCBoPTApLGFlcyhjb2xvciA9IHRlbXApLCBhbHBoYSA9MC41KSArIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJncmVlbiIsIGhpZ2ggPSAicmVkIikKYGBgCiMjIyMgTm93IGNyZWF0ZSB0aGUgc2FtZSBwbG90IGZvciBub24gd29ya2luZyBkYXlzOgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBzdWJzZXQoeCA9IGJpa2UsIHN1YnNldCA9IHdvcmtpbmdkYXkgPT0gMCksIGFlcyh4ID0gaG91ciwgeSA9IGNvdW50KSkgKyBnZW9tX3BvaW50KHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3PTEsIGg9MCksYWVzKGNvbG9yID0gdGVtcCksIGFscGhhID0wLjUpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gImdyZWVuIiwgaGlnaCA9ICJyZWQiKQpgYGAKIyMjIyBZb3Ugc2hvdWxkIGhhdmUgbm90aWNlZCB0aGF0IHdvcmtpbmcgZGF5cyBoYXZlIHBlYWsgYWN0aXZpdHkgZHVyaW5nIHRoZSBtb3JuaW5nICh+OGFtKSBhbmQgcmlnaHQgYWZ0ZXIgd29yayBnZXRzIG91dCAofjVwbSksIHdpdGggc29tZSBsdW5jaHRpbWUgYWN0aXZpdHkuIFdoaWxlIHRoZSBub24td29yayBkYXlzIGhhdmUgYSBzdGVhZHkgcmlzZSBhbmQgZmFsbCBmb3IgdGhlIGFmdGVybm9vbgoKIyMjIyBOb3cgbGV0J3MgY29udGludWUgYnkgdHJ5aW5nIHRvIGJ1aWxkIGEgbW9kZWwsIHdlJ2xsIGJlZ2luIGJ5IGp1c3QgbG9va2luZyBhdCBhIHNpbmdsZSBmZWF0dXJlLgoKIyMgQnVpbGRpbmcgdGhlIE1vZGVsCiMjIyMgVXNlIGxtKCkgdG8gYnVpbGQgYSBtb2RlbCB0aGF0IHByZWRpY3RzIGNvdW50IGJhc2VkIHNvbGVseSBvbiB0aGUgdGVtcCBmZWF0dXJlLCBuYW1lIGl0IHRlbXAubW9kZWwKYGBge3J9CnRlbXAubW9kZWwgPC0gbG0oY291bnQgfiB0ZW1wLCBkYXRhID0gYmlrZSkKYGBgCiMjIyMgR2V0IHRoZSBzdW1tYXJ5IG9mIHRoZSB0ZW1wLm1vZGVsCmBgYHtyfQpzdW1tYXJ5KHRlbXAubW9kZWwpCmBgYAojIyMjIEhvdyBtYW55IGJpa2UgcmVudGFscyB3b3VsZCB3ZSBwcmVkaWN0IGlmIHRoZSB0ZW1wZXJhdHVyZSB3YXMgMjUgZGVncmVlcyBDZWxzaXVzPyBDYWxjdWxhdGUgdGhpcyB0d28gd2F5czoKKiBVc2luZyB0aGUgdmFsdWVzIHdlIGp1c3QgZ290IGFib3ZlCiogVXNpbmcgdGhlIHByZWRpY3QoKSBmdW5jdGlvbgpZb3Ugc2hvdWxkIGdldCBhcm91bmQgMjM1LjMgYmlrZXMuCmBgYHtyfQo2LjA0NjIgKyA5LjE3MDUqMjUKYGBgCmBgYHtyfQpwcmVkaWN0KHRlbXAubW9kZWwsIGRhdGEuZnJhbWUodGVtcCA9IGMoMjUpKSkKYGBgCiMjIyMgVXNlIHNhcHBseSgpIGFuZCBhcy5udW1lcmljIHRvIGNoYW5nZSB0aGUgaG91ciBjb2x1bW4gdG8gYSBjb2x1bW4gb2YgbnVtZXJpYyB2YWx1ZXMuCmBgYHtyfQpiaWtlJGhvdXIgPC0gc2FwcGx5KGJpa2UkaG91ciwgYXMubnVtZXJpYyApCmBgYAojIyMjIEZpbmFsbHkgYnVpbGQgYSBtb2RlbCB0aGF0IGF0dGVtcHRzIHRvIHByZWRpY3QgY291bnQgYmFzZWQgb2ZmIG9mIHRoZSBmb2xsb3dpbmcgZmVhdHVyZXMuIEZpZ3VyZSBvdXQgaWYgdGhlcmVzIGEgd2F5IHRvIG5vdCBoYXZlIHRvIHBhc3Mvd3JpdGUgYWxsIHRoZXNlIHZhcmlhYmxlcyBpbnRvIHRoZSBsbSgpIGZ1bmN0aW9uLiBIaW50OiBTdGFja092ZXJmbG93IG9yIEdvb2dsZSBtYXkgYmUgcXVpY2tlciB0aGFuIHRoZSBkb2N1bWVudGF0aW9uLgpzZWFzb24KaG9saWRheQp3b3JraW5nZGF5CndlYXRoZXIKdGVtcApodW1pZGl0eQp3aW5kc3BlZWQKaG91ciAoZmFjdG9yKQpgYGB7cn0KbG0ubW9kZWwgPC0gbG0oY291bnQgfiAuIC1jYXN1YWwgLSByZWdpc3RlcmVkIC1kYXRldGltZSAtYXRlbXAsYmlrZSkKYGBgCiMjIyMgR2V0IHRoZSBzdW1tYXJ5IG9mIHRoZSBtb2RlbApgYGB7cn0Kc3VtbWFyeShsbS5tb2RlbCkKYGBgCiMjIyMgRGlkIHRoZSBtb2RlbCBwZXJmb3JtIHdlbGwgb24gdGhlIHRyYWluaW5nIGRhdGE/IFdoYXQgZG8geW91IHRoaW5rIGFib3V0IHVzaW5nIGEgTGluZWFyIE1vZGVsIG9uIHRoaXMgZGF0YT8KCiMjIyMgWW91IHNob3VsZCBoYXZlIG5vdGljZWQgdGhhdCB0aGlzIHNvcnQgb2YgbW9kZWwgZG9lc24ndCB3b3JrIHdlbGwgZ2l2ZW4gb3VyIHNlYXNvbmFsIGFuZCB0aW1lIHNlcmllcyBkYXRhLiBXZSBuZWVkIGEgbW9kZWwgdGhhdCBjYW4gYWNjb3VudCBmb3IgdGhpcyB0eXBlIG9mIHRyZW5kLCByZWFkIGFib3V0IFJlZ3Jlc3Npb24gRm9yZXN0cyBmb3IgbW9yZSBpbmZvIGlmIHlvdSdyZSBpbnRlcmVzdGVkISBGb3Igbm93LCBsZXQncyBrZWVwIHRoaXMgaW4gbWluZCBhcyBhIGxlYXJuaW5nIGV4cGVyaWVuY2UgYW5kIG1vdmUgb24gdG93YXJkcyBjbGFzc2lmaWNhdGlvbiB3aXRoIExvZ2lzdGljIFJlZ3Jlc3Npb24hCgojIyMgQVJJTUEgbW9kZWwgY2FuIGFsc28gaXMgYmV0dGVyIG9wdGlvbiBpbiBwcmVkaWN0aW5nIHRpbWUgc2VyaWVzCgojIyMjIE9wdGlvbmFsOiBTZWUgaG93IHdlbGwgeW91IGNhbiBwcmVkaWN0IGZvciBmdXR1cmUgZGF0YSBwb2ludHMgYnkgY3JlYXRpbmcgYSB0cmFpbi90ZXN0IHNwbGl0LiBCdXQgaW5zdGVhZCBvZiBhIHJhbmRvbSBzcGxpdCwgeW91ciBzcGxpdCBzaG91bGQgYmUgImZ1dHVyZSIgZGF0YSBmb3IgdGVzdCwgInByZXZpb3VzIiBkYXRhIGZvciB0cmFpbi4KCiMjIEdyZWF0IEpvYiEK